#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include "font.h"
#include "lv_draw.h"
#include <stdint.h>

char color_buf[800 * 480 * 4] = {0};

unsigned int *g_fb = NULL;

int g_fd_lv;

font *g_font=NULL;;
void lv__reak_draw_point(int x, int y, unsigned int color) {
    static int last_x = -1, last_y = -1;
    static unsigned int *current_ptr = NULL;
    if (y == last_y && x == last_x + 1) {
        *(++current_ptr) = color; // 直接写入下一个内存地址
        last_x = x;
        return;
    }

    current_ptr = g_fb + y * LCD_WIDTH + x;
    *current_ptr = color;
    last_x = x;
    last_y = y;
}

unsigned int lv_reader_point(int x, int y) {
    static int last_y = -1;
    static unsigned int *row_ptr = NULL;
    
    if (y == last_y && row_ptr != NULL) {
        if (x == 0) {
            row_ptr = g_fb + y * LCD_WIDTH;
        }
        return row_ptr[x];
    }

    row_ptr = g_fb + y * LCD_WIDTH;
    last_y = y;
    return row_ptr[x];
}

// 清屏操作
void lv_clear_fill(unsigned int color)
{
    int x, y;

    for (y = 479; y >= 0; y--)
    {
        for (x = 0; x < 800; x++)
        {
            // 对每个像素点进行赋值
            lv__reak_draw_point(x, y, color);
        }
    }
}

void lv_fill_clean_bmp(int x, int y, int width, int height, unsigned int color) {
    int x_e = (x + width > LCD_WIDTH) ? LCD_WIDTH : x + width;
    int y_e = (y + height > LCD_HEIGHT) ? LCD_HEIGHT : y + height;
    unsigned int *ptr_start = g_fb + y * LCD_WIDTH + x;
    int line_len = x_e - x;

    for (int cur_y = y; cur_y < y_e; cur_y++) {
        unsigned int *ptr = ptr_start;
        for (int i = 0; i < line_len; i++) {
            *ptr++ = color;
        }
        ptr_start += LCD_WIDTH;
    }
}


int lv_draw_paint_bmp(const char *pathname, int x, int y) {
    int fd_bmp = open(pathname, O_RDONLY);
    if (fd_bmp < 0) {
        printf("open %s fail\n", pathname);
        return -1;
    }

    // 1. 读取文件头
    BITMAPFILEHEADER file_head;
    BITMAPINFOHEADER info_head;
    read(fd_bmp, &file_head, sizeof(file_head));
    read(fd_bmp, &info_head, sizeof(info_head));

    // 2. 计算行对齐字节数
    int line_size = (info_head.biWidth * 3 + 3) & ~3; 
    char *bmp_buf = malloc(line_size * info_head.biHeight);

    // 3. 逐行读取BMP数据
    lseek(fd_bmp, sizeof(file_head) + sizeof(info_head), SEEK_SET);
    for (int row = 0; row < info_head.biHeight; row++) {
        read(fd_bmp, bmp_buf + row * line_size, line_size);
    }
    close(fd_bmp);

    // 4. 显示优化核心逻辑
    unsigned int *fb_ptr = g_fb + y * 800 + x; // 起始位置
    for (int row = info_head.biHeight - 1; row >= 0; row--) {
        char *line_ptr = bmp_buf + row * line_size;
        for (int col = 0; col < info_head.biWidth; col++) {
            *fb_ptr++ = (line_ptr[2] << 16) | (line_ptr[1] << 8) | line_ptr[0];
            line_ptr += 3;
        }
        fb_ptr += 800 - info_head.biWidth; // 跳转到下一行起始
    }

    free(bmp_buf);
    return 0;
}

int lv_draw_pokemon(const char *pathname, int x, int y) {
    int fd_bmp = open(pathname, O_RDONLY);
    if (fd_bmp < 0) {
        perror("open fail");
        return -1;
    }

    // 一次性读取文件头和信息头
    uint8_t header_buf[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)];
    read(fd_bmp, header_buf, sizeof(header_buf));
    BITMAPFILEHEADER *file_head = (BITMAPFILEHEADER*)header_buf;
    BITMAPINFOHEADER *info_head = (BITMAPINFOHEADER*)(header_buf + sizeof(BITMAPFILEHEADER));

    // 计算像素数据大小并读取
    int bmp_rgb_size = info_head->biWidth * info_head->biHeight * (info_head->biBitCount / 8);
    char *bmp_buf = malloc(bmp_rgb_size);
    read(fd_bmp, bmp_buf, bmp_rgb_size);
    close(fd_bmp);

    // 优化绘制逻辑
    int width = info_head->biWidth;
    int height = info_head->biHeight;
    int x_e = x + width;
    int y_e = y + height;

    // 按行连续绘制
    for (int row = 0; row < height; row++) {
        int y_pos = y + row;
        unsigned int *fb_ptr = g_fb + y_pos * LCD_WIDTH + x; // 帧缓冲行起始指针
        
        for (int col = 0; col < width; col++) {
            int idx = (row * width + col) * 3; // 像素数据索引
            unsigned int b = bmp_buf[idx];
            unsigned int g = bmp_buf[idx + 1];
            unsigned int r = bmp_buf[idx + 2];
            unsigned int color = (r << 16) | (g << 8) | b;

            // 透明色处理：跳过接近纯红的像素（0xF10000）
            if (color >= 0xF10000 && color <= 0xF1FFFF) continue;
            
            *fb_ptr++ = color; // 直接写入帧缓冲
        }
    }
    free(bmp_buf);
    return 0;
}

int lv_font_select_chinese(const char *pathname)
{
	if(pathname == NULL)
	{
		printf("字体路径参数为NULL\n");
		
		return -1;
	}
	
    if (access(pathname, F_OK) == -1)
    {
		printf("%s 不存在\n",pathname);
		
		return -1;
    }
	
	//若以前加载过字体，卸载字体
	if(g_font)
	{
		fontUnload(g_font);
		g_font=NULL;
	}
		
	//加载字体
	g_font= fontLoad((char *)pathname);
	
	if(g_font==NULL)
	{
		printf("加载 %s 失败\n",pathname);
		
		return -1;		
	}
	  
	return 0;
}

int is_utf8_chinese(char ch) {
    return (ch & 0xE0) == 0xE0;  // 判断是否是UTF-8中文字符的第一个字节
}

int is_utf8_english(char ch) {
    return (ch & 0x80) == 0x00;  // 判断是否是UTF-8英文字符的字节
}

int utf8_strlen(const char* str,unsigned int *cn_total,unsigned int *en_total) 
{
    int len = 0;
    int i = 0;

    while (str[i] != '\0') {
        if (is_utf8_chinese(str[i])) {
            len+=3;  // 中文字符占三个字节
            i += 3; 
            (*cn_total)++;
        }
        else if (is_utf8_english(str[i])) {
            len++;  // 英文字符占一个字节
            i++;
            (*en_total)++;    
        }
    }

    return len;
}



int lv_draw_string_bmp(const char *str, int x, int y, unsigned int color, unsigned int font_size) {
    if (g_font == NULL) {
        printf("目前还没有加载字体，无法显示...\n");
        return -1;
    }

    unsigned int cn_total = 0, en_total = 0;
    int len = utf8_strlen(str, &cn_total, &en_total);
    
    fontSetSize(g_font, font_size);
    
    unsigned int draw_width = cn_total * font_size + en_total * font_size / 2;
    unsigned int draw_height = font_size;
    
    int x_end = x + draw_width;
    int y_end = y + draw_height;
    if (x_end > LCD_WIDTH) x_end = LCD_WIDTH;
    if (y_end > LCD_HEIGHT) y_end = LCD_HEIGHT;
    draw_width = x_end - x;
    draw_height = y_end - y;
    
    if (draw_width <= 0 || draw_height <= 0) 
        return -1;
    
    bitmap *bm = createBitmap(draw_width, draw_height, 4);
    if (!bm) return -1;
    
    unsigned int *p = (unsigned int *)bm->map;
    for (int row = 0; row < draw_height; row++) {
        unsigned int *fb_ptr = g_fb + (y + row) * LCD_WIDTH + x;
        memcpy(p, fb_ptr, draw_width * sizeof(unsigned int));
        p += draw_width;
    }
    
    fontPrint(g_font, bm, 0, 0, (char *)str, color, 0);
    
    unsigned int *src = (unsigned int *)bm->map;
    for (int row = 0; row < draw_height; row++) {
        unsigned int *dst = g_fb + (y + row) * LCD_WIDTH + x;
        memcpy(dst, src, draw_width * sizeof(unsigned int));
        src += draw_width;
    }
    
    destroyBitmap(bm);
    return 0;
}

int lcd_open(const char *pathname)
{
    // 打开/dev/fb0
    int g_fd_lv = open(pathname, O_RDWR);

    if (g_fd_lv < 0)
    {
        printf("open %s fail\n", pathname);
        return -1;
    }

    // 将设备文件/dev/fb0映射到内存
    g_fb = mmap(NULL,                   // 映射区的起始地址由系统自动分配
                800 * 480 * 4,          // 映射内存的大小，往往填写文件的大小
                PROT_READ | PROT_WRITE, // 映射区的保护形式，当前是可读可写
                MAP_SHARED,             // 共享，把映射内存的数据同步到文件
                g_fd_lv,               // 映射的文件描述符
                0);                     // 文件的偏移量，0就不需要进行的偏移

    if (g_fb == MAP_FAILED)
    {
        printf("mmap fail\n");
        return -1;
    }

    return 0;
}

int lv_close(void)
{
    if (g_fd_lv > 0)
        close(g_fd_lv);

    // 解除内存映射
    if (g_fb)
	{
		munmap(g_fb, 800 * 480 * 4);
		g_fb=NULL;
	}
        
	
	//若以前加载过字体，卸载字体
	if(g_font)
	{
		fontUnload(g_font);
		g_font=NULL;
	}

    return 0;
}

int lv_draw_paint_bmp_to_memory(const char *path, Image *img) {
    int fd_bmp = open(path, O_RDONLY);
    if (fd_bmp == -1) {
        return -1;
    }

    unsigned char bmp_head[54];
    if (read(fd_bmp, bmp_head, 54) != 54) {
        close(fd_bmp);
        return -1;
    }

    img->width = *(int *)&bmp_head[18];
    img->height = *(int *)&bmp_head[22];
    if (img->width <= 0 || img->height <= 0 || img->width > 4096 || img->height > 4096) {
        close(fd_bmp);
        return -1;
    }

    int line_bytes = (img->width * 3 + 3) & ~3;
    img->data = malloc(img->width * img->height * sizeof(unsigned int));
    if (!img->data) {
        close(fd_bmp);
        return -1;
    }

    lseek(fd_bmp, 54, SEEK_SET);
    unsigned char *line_buf = malloc(line_bytes);
    if (!line_buf) {
        free(img->data);
        close(fd_bmp);
        return -1;
    }

    unsigned int *pixel = img->data;
    for (int y = 0; y < img->height; y++) {
        if (read(fd_bmp, line_buf, line_bytes) != line_bytes) {
            free(line_buf);
            free(img->data);
            close(fd_bmp);
            return -1;
        }
        for (int x = 0; x < img->width; x++) {
            unsigned char *pix = line_buf + x * 3;
            *pixel++ = (pix[2] << 16) | (pix[1] << 8) | pix[0];
        }
    }

    free(line_buf);
    close(fd_bmp);
    return 0;
}

void draw_image_from_memory(Image *img, int x0, int y0) {
    unsigned int *pixel = img->data;
    for (int y = 0; y < img->height; y++) {
        for (int x = 0; x < img->width; x++) {
            lv__reak_draw_point(x0 + x, y0 + y, *pixel++);
        }
    }
}